﻿#ifndef OBSERVER_H
#define OBSERVER_H

#include <QList>
#include <QMutex>
#include <QObject>


/**
 * @ref 表示观察者接口。
 */
template <typename T>
class IObserver
{
public:
    // 构造。
    IObserver(){}
    // 析构。
    virtual ~IObserver(){}
    /**
    * @brief 目标发生变化时，通知调用。
    * @param  args 变化的数据或参数。
    */
    virtual void doProcess(const T& args) = 0;
};

/**
 * @ref 表示被观察的对象。
 */
template <typename T>
class Observable
{
public:
    Observable(){}
    virtual ~Observable(){}
    /**
    * @brief 注册观察者。
    * @param  IObserver<T>* handle  观察者实例。
    * @return 注册成功返回true。
    */
    bool attach(IObserver<T>* handle)
    {
        if (!handle)
        {
            return false;
        }
        if(!m_lstObs.contains(handle) )
        {
            lock();
            if(!m_lstObs.contains(handle) )
            {
                m_lstObs.append(handle);
            }
            unlock();
            return true;
        }
        return false;
    }
    /**
    * @brief 注销观察者。
    * @param IObserver<T> *handle  观察者。
    * @return 注销成功返回true。
    */
    bool detach(IObserver<T> *handle)
    {
        if (!handle) return false;
        bool removed = false;
        lock();
        removed = m_lstObs.removeOne(handle);
        unlock();
        return removed;
    }
    /**
    * @brief 移除所有观察者。
    */
    void detachAll()
    {
        if(m_lstObs.length()<=0)
        {
            return;
        }
        lock();
        m_lstObs.clear();
        unlock();
    }
    /**
    * @brief 通知观察者。
    * @param const T &args 通知参数。若状态变化，则遍历观察者，逐个通知更新
    */
    void notify(const T &args)
    {
        QList<IObserver<T>*> tmplst;
        lock();
        tmplst.append(m_lstObs);
        unlock();
        typename  QList<IObserver<T>*>::iterator itr = tmplst.begin();
        for (; itr != tmplst.end(); itr++)
        {
            (*itr)->doProcess(args);
        }
    }
    /**
    * @brief 获取当前观察者数量。
    */
    int getCount()
    {
        return m_lstObs.size();
    }
private:
    //保证目标唯一性
    QList<IObserver<T>*> m_lstObs;
    // 互斥对象。
    QMutex m_mutex;
private:
    /**
    * @brief 锁定观察者。
    */
    void lock(){m_mutex.lock();}
    /**
    * @brief 解除锁定。
    */
    void unlock(){ m_mutex.unlock();}
};


#endif // OBSERVER_H
